##我发现使用指标/macd.py和蓝柱.py中的示例，单独运行可以获得最近的金叉时间和蓝柱时间
##我想循环基础配置里面监测的股票每分钟监测一次，使用示例的方式，如果金叉和蓝柱在当前时间范围内，可以调用行情监控的买入方法进行买入
##分钟级别监测即可
from xtquant import xtdata
import time
from datetime import datetime
from typing import Dict
import pandas as pd

from 基础配置 import settings
from 行情监控 import MarketMonitor
from 指标.MACD import MACDSignalCalculator, MACDConfig
from 指标.蓝柱独立 import BlueColumnCalculator
from 指标.涨跌幅 import UpDownCalculator


class MinuteWatcher:

	def __init__(self, trade_cmd_queue=None, log_callback=None):
		# 在子进程中仅用于下发交易指令到主界面队列
		self.monitor = MarketMonitor(trader=None, log_callback=log_callback, trade_cmd_queue=trade_cmd_queue)
		self.macd_calc = MACDSignalCalculator(xtdata, use_warmup=False)
		self.blue_calc = BlueColumnCalculator(xtdata)
		self.updown_calc = UpDownCalculator(xtdata=xtdata)
		self.code_to_name: Dict[str, str] = {s["all_code"]: s["name"] for s in settings.STOCK_CODE}
		self.last_signal_key: Dict[str, str] = {}

	def _now_ts(self) -> float:
		return time.time()

	def _within_seconds(self, ts_str: str, window_sec: int) -> bool:
		try:
			dt = datetime.strptime(ts_str, '%Y-%m-%d %H:%M:%S')
			return abs((datetime.now() - dt).total_seconds()) <= window_sec
		except Exception:
			return False


	def _align_next_minute_sleep(self):
		now = datetime.now()
		remain = 30 - (now.second % 30)
		if remain <= 0:
			remain = 30
		time.sleep(remain)

	def _get_current_price(self, code: str) -> float:
		try:
			today = datetime.now().strftime('%Y%m%d')
			data = xtdata.get_local_data(stock_list=[code], period='1m', start_time=today, end_time=today)
			if data and code in data and not data[code].empty:
				df = data[code]
				price_col = next((c for c in ['close', 'lastPrice', 'price', 'last', 'current'] if c in df.columns), None)
				if price_col:
					val = df.iloc[-1][price_col]
					try:
						return float(val)
					except Exception:
						return 0.0
			return 0.0
		except Exception:
			return 0.0

	def _maybe_buy(self, code: str, reason_macd: str, price: float, updown_info: Dict = None):
		print(f"{code}:分钟级别{reason_macd}")
		if not self.monitor._is_trading_time():
			return
		if reason_macd=="蓝柱":
			return
		if code=="513130.SH":
			return
		##蓝柱的购买时间为上午10:00到11.30之间
		# now = datetime.now()
		# current_time = now.time()
		# start_time = datetime.strptime("10:00", "%H:%M").time()
		# end_time = datetime.strptime("11:30", "%H:%M").time()
		# if not (start_time <= current_time <= end_time):
		# 	print(f"{code}:蓝柱信号不在交易时间(10:00-11:30)内，跳过")
		# 	return

		name = self.code_to_name.get(code, code)
		order_remark = {"level": 0, "macd": reason_macd}
		try:
			import json
			remark_str = json.dumps(order_remark, ensure_ascii=False)
		except Exception:
			remark_str = str(order_remark)

		# 直接使用传入的涨跌幅信息，避免重复计算
		self.monitor.execute_golden_cross_buy(code, name, price, remark_str, updown_info)

	def run(self, window_sec: int = 90):
		codes = [s["all_code"] for s in settings.STOCK_CODE]
		print(f"分钟监控启动，监控 {len(codes)} 只股票，每分钟检测一次。")
		while True:
			start_minute = datetime.now().strftime('%Y-%m-%d %H:%M')
			for code in codes:
				try:
					# 1) MACD 金叉检测（同花顺初始化）
					macd = self.macd_calc.detect_macd_signals(
						code,
						fast=MACDConfig.FAST_EMA,
						slow=MACDConfig.SLOW_EMA,
						signal=MACDConfig.SIGNAL_EMA,
						include_auction=True,
						use_simple_init=True
					)
					goldens = macd.get('golden_cross', []) or []
					buy_triggered = False
					last_golden_str = "-"
					last_golden_price = 0.0
					golden_signal = None  # 保存金叉信号待涨跌幅计算后处理
					if goldens:
						last_gc = goldens[-1]
						ts = last_gc.get('time', '')
						price = float(last_gc.get('price', 0) or 0)
						last_golden_str = ts or "-"
						last_golden_price = price
						key = f"golden_{ts}_{price:.6f}"
						if self._within_seconds(ts, window_sec) and self.last_signal_key.get(code) != key:
							if price <= 0:
								price = self._get_current_price(code)
							golden_signal = {"key": key, "price": price}  # 暂存信号

					# 2) 蓝柱检测（先取全量用于日志，再按窗口自行过滤触发买入）
					last_blue_str = "-"
					last_blue_price = 0.0
					blue_all_list = []
					blue_signal = None  # 保存蓝柱信号待涨跌幅计算后处理
					try:
						blue_all = self.blue_calc.detect_blue_signals(code, include_auction=True,
																	  return_all_signals=True)
						blue_all_list = blue_all.get('blue_column', []) or []
						if blue_all_list:
							_last = blue_all_list[-1]
							last_blue_str = _last.get('time', '-') or "-"
							last_blue_price = float(_last.get('price', 0) or 0)
					except Exception:
						pass
					# 仅当最后蓝柱在窗口内，且本分钟未因金叉买入时触发
					if blue_all_list:
						last_blue = blue_all_list[-1]
						ts = last_blue.get('time', '')
						price = float(last_blue.get('price', 0) or 0)
						key = f"blue_{ts}_{price:.6f}"
						if self._within_seconds(ts, window_sec) and self.last_signal_key.get(code) != key:
							if price <= 0:
								price = self._get_current_price(code)
							blue_signal = {"key": key, "price": price}  # 暂存信号

					# # 3) 获取当前最新价格和涨跌幅信息
					# current_price = self._get_current_price(code)  # 获取当前最新价格，而不是历史金叉/蓝柱价格
					# updown_str = "-"
					# updown_value = 0.0
					# updown_info = None
					# print(f"{code}:当前价格{current_price}")
					# try:
					# 	if current_price > 0:
					# 		updown_info = self.updown_calc.get_updown(code, current_price)
					# 		if updown_info and isinstance(updown_info, dict):
					# 			updown_value = updown_info.get("updown", 0)
					# 			if updown_value != 0:
					# 				updown_str = f"{updown_value:.2f}%"
					# 		else:
					# 			print(f"{code}:涨跌幅信息无效: updown_info={updown_info}")
					# 	else:
					# 		print(f"{code}:当前价格无效: {current_price}")
					# except Exception as e2:
					# 	print(f"{code}:获取涨跌幅失败: {e2}")
					# 	import traceback
					# 	traceback.print_exc()
					#
					# # 4) 在获取涨跌幅后，根据信号触发买入
					updown_info = None
					if golden_signal:
						self.last_signal_key[code] = golden_signal["key"]
						self._maybe_buy(code, "金叉", golden_signal["price"], updown_info)
						buy_triggered = True
					#
					# # if blue_signal and not buy_triggered:
					# # 	self.last_signal_key[code] = blue_signal["key"]
					# # 	self._maybe_buy(code, "蓝柱", blue_signal["price"], updown_info)
					#
					# 每分钟输出最后一次金叉、蓝柱时间（含价格）和涨跌幅
					lg_price_str = f"{last_golden_price:.3f}" if last_golden_price else "-"
					lb_price_str = f"{last_blue_price:.3f}" if last_blue_price else "-"
					updown_str = 0
					print(f"{code} 最后金叉: {last_golden_str} 价:{lg_price_str} | 最后蓝柱: {last_blue_str} 价:{lb_price_str} | 涨跌幅: {updown_str}")


				except Exception as e:
					print(f"{code} 分钟检测异常: {e}")
			# 对齐到下一分钟开始
			self._align_next_minute_sleep()



if __name__ == "__main__":
	watcher = MinuteWatcher()
	# 默认窗口90秒，覆盖分钟边界抖动与数据延迟，可按需调整为60~180秒
	watcher.run(window_sec=90)
